package com.enbatis.mybatisplugs.controller;

import com.enbatis.mybatisplugs.base.BaseController;
import com.enbatis.mybatisplugs.commons.utils.IdWorker;
import com.enbatis.mybatisplugs.commons.utils.ResultReturn;
import com.enbatis.mybatisplugs.entity.SysUser;
import com.enbatis.mybatisplugs.entity.WorkGroup;
import com.enbatis.mybatisplugs.entity.dto.FlowTaskDTO;
import com.enbatis.mybatisplugs.entity.dto.ProcessDefDTO;
import com.enbatis.mybatisplugs.entity.vo.SysUserVO;
import com.enbatis.mybatisplugs.plugin.Pages;
import com.enbatis.mybatisplugs.service.SysUserService;
import com.enbatis.mybatisplugs.service.WorkGroupService;
import com.github.pagehelper.Page;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.User;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;
@Slf4j
@RestController
@RequestMapping("v1/activiti")
public class ActivitiController extends BaseController {
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ProcessEngine processEngine;

    @Autowired
    private WorkGroupService workGroupService;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private TaskService taskService;

    @PostMapping(value = "/upload")
    public void uploadFlowFile(@RequestParam("file") MultipartFile file) throws Exception  {
        InputStream in = file.getInputStream();
        ZipInputStream zipInputStream = new ZipInputStream(in);
        Deployment deployment = processEngine.getRepositoryService()//获取流程定义和部署对象相关的Service
                .createDeployment()//创建部署对象
                .addZipInputStream(zipInputStream)//使用zip方式部署，将helloworld.bpmn和helloworld.png压缩成zip格式的文件
                .deploy();//完成部署
        System.out.println("部署ID："+deployment.getId());//1
        System.out.println("部署时间："+deployment.getDeploymentTime());
    }


    @PostMapping(value = "/page")
    public ResultReturn<Pages<ProcessDefDTO>> getProcessList()  {
        Pages<ProcessDefDTO> definitionPages = new Pages<>();
        Page<ProcessDefinitionEntity> page=  getPage();
        ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
        //总条数
        Long size = query.count();

      int s=  page.getPageNum();
      int e=  page.getPageSize();

        List<ProcessDefinition> list=  query.listPage(s-1,e-1);
        List<ProcessDefDTO> myList = new ArrayList<>();
        //将查询出来的流程定义中的数据，加载到我们自己的list中
        for(ProcessDefinition def : list){
            ProcessDefDTO entity = new ProcessDefDTO();
            entity.setId(def.getId());
            entity.setName(def.getName());
            entity.setKey(def.getKey());
            entity.setDeploymentId(def.getDeploymentId());
            entity.setResourceName(def.getResourceName());
            entity.setVersion(def.getVersion());
            myList.add(entity);
        }
        definitionPages.setTotal(size);
        definitionPages.setRecords(myList);
        int max = page.getPageSize();
        int total = size.intValue();
        int pages = total%max == 0 ? (total/max) : (total/max)+1;
        definitionPages.setPages(pages);
        return success(definitionPages);

    }

    @PostMapping("/add_work_group")
    public ResultReturn<Boolean> add(@RequestBody WorkGroup workGroup){
        return  saveTaskGroup(workGroup);
    }


    @PostMapping("/add_group_user")
    public ResultReturn<Boolean> addGroupUser(@RequestParam("groupId")Long groupId,@RequestParam("userIds") Long [] userIds){
        IdentityService identityService = processEngine.getIdentityService();//
        for (Long userId:userIds) {
            User userDb = identityService.createUserQuery().userId(String.valueOf(userId)).singleResult();
            if (null==userDb){
                User user= identityService.newUser(String.valueOf(userId));
                user.setId(String.valueOf(userId));
                identityService.saveUser(user);
            }
            // 查询用户组中的用户
            List<User> userList = identityService.createUserQuery()
                    .memberOfGroup(String.valueOf(groupId)).userId(String.valueOf(userId))
                    .list();
            if (CollectionUtils.isEmpty(userList)){
                identityService.createMembership(String.valueOf(userId),String.valueOf(groupId));
            }
        }
        return success(true);
    }


    @PostMapping(value = "/save")
    public ResultReturn<Boolean> saveTaskGroup( WorkGroup workGroup){

          if (StringUtils.isBlank(workGroup.getName())){
              success("组名称不能为空");
          }
        if (StringUtils.isBlank(workGroup.getKeyWord())){
            success("关键字不能为空");
        }
        workGroup.setId(IdWorker.getId());
       if (workGroupService.insert(workGroup)!=null){
           IdentityService identityService = processEngine.getIdentityService();//
            Group group= identityService.newGroup(workGroup.getName());
            group.setName(workGroup.getName());
            group.setId(String.valueOf(workGroup.getId()));
            identityService.saveGroup(group);
       }

        return success(true);
    }

    @ApiOperation(value = "分页列表", notes = "分页查询数据列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", value = "请求数据的页码", required = true, paramType = "query", dataType = "int"),
            @ApiImplicitParam(name = "rows", value = "每页条数", required = true, paramType = "query", dataType = "int"),
            @ApiImplicitParam(name = "sidx", value = "排序字段", paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "sord", value = "排序方式", paramType = "query", dataType = "String"),
    })
    @PostMapping("/page_work_group_user")
    public ResultReturn<Pages<SysUserVO>> getPageGroupVO(@RequestBody SysUserVO userVO){
        Page<SysUserVO> page= getPage();
        if (null != userVO.getGroupId()){
            IdentityService identityService = processEngine.getIdentityService();//
            List<User> userList = identityService.createUserQuery()
                    .memberOfGroup(String.valueOf(userVO.getGroupId()))
                    .list();
            List<Long> userIds = new ArrayList<>();

            for ( User user:userList) {
                userIds.add(Long.parseLong(user.getId()));
            }

            userVO.setUserIds(userIds);
        }
        return success(sysUserService.pageVO(page,userVO));
    }



    @PostMapping(value = "/start_leave_check")
    public ResultReturn<Boolean> startLeaveCheck( WorkGroup workGroup){
        RuntimeService runtimeService = processEngine.getRuntimeService();
        runtimeService.startProcessInstanceById("leave");
        return success(true);
    }




    @PostMapping(value = "/page_task_list")
    public ResultReturn<Pages<FlowTaskDTO>> getFlowTaskList(@RequestBody FlowTaskDTO dto)  {
        dto.setUserId(getAccount().getId());
        if (dto.getUserId()==null){
            return success(new Pages<>());
        }

        List<String> candidateGroups = workGroupService.listCandidateGroup(dto.getUserId().toString());
        if (CollectionUtils.isEmpty(candidateGroups)){
            return success(new Pages<>());
        }

          Page<FlowTaskDTO> page=    getPage();
        List<Task> list = processEngine.getTaskService()// 与正在执行的任务管理相关的Service
                .createTaskQuery()// 创建任务查询对象
                /** 查询条件（where部分） */
                .taskCandidateGroupIn(candidateGroups)// 组任务的办理人查询
                /** 排序 */
                .orderByTaskCreateTime().asc()// 使用创建时间的升序排列
                /** 返回结果集 */
                .listPage(page.getPageNum()-1,page.getPageSize()-1);// 返回列表
        Long size = processEngine.getTaskService()// 与正在执行的任务管理相关的Service
                .createTaskQuery()// 创建任务查询对象
                /** 查询条件（where部分） */
                .taskCandidateGroupIn(candidateGroups)// 组任务的办理人查询
                /** 排序 */
                .orderByTaskCreateTime().asc().count();
        List<FlowTaskDTO> myList = new ArrayList<>();
        //将查询出来的流程定义中的数据，加载到我们自己的list中

        ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
        RuntimeService runtimeService = processEngine.getRuntimeService();

        for(Task task : list){
            FlowTaskDTO taskDTO = new FlowTaskDTO();
            taskDTO.setId(task.getId());
            taskDTO.setName(task.getName());
            taskDTO.setAssignee(task.getAssignee());
            taskDTO.setCreateTime(task.getCreateTime());
            taskDTO.setExecutionId(task.getExecutionId());
            taskDTO.setProcessDefinitionId(task.getProcessDefinitionId());
            taskDTO.setProcessInstanceId(task.getProcessInstanceId());

            query.processDefinitionId(task.getProcessDefinitionId());
            //最新版本过滤
            query.latestVersion();
            //查询
            ProcessDefinition definition = query.singleResult();
            if (null != definition) {
                taskDTO.setProcessName(definition.getName());
            }
            Map<String,Object> map= taskService.getVariables(task.getId());
            Object reason=  map.get("applyReason");
            if (null != reason){
                taskDTO.setApplyReason(reason.toString());
            }
            Object applyuserid=  map.get("${applyuserid}");
            if (null!=applyuserid){
                Long userId =Long.parseLong(applyuserid.toString());
                taskDTO.setApplyUserId(userId);
                SysUser user= sysUserService.getById(userId);

                taskDTO.setApplyUserName(user.getName());
            }


            //2  通过任务对象获取流程实例
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
            //3 通过流程实例获取“业务键”
            String businessKey = pi.getBusinessKey();
            if (StringUtils.isNotBlank(businessKey)){
                taskDTO.setBusinessId(Long.parseLong(businessKey));
            }

             myList.add(taskDTO);
        }
        Pages<FlowTaskDTO> taskDTOPages =new Pages<>();

        taskDTOPages.setTotal(size);
        taskDTOPages.setRecords(myList);
        int max = page.getPageSize();
        int total = size.intValue();
        int pages = total%max == 0 ? (total/max) : (total/max)+1;
        taskDTOPages.setPages(pages);
        return success(taskDTOPages);
    }




    @GetMapping(value = "/watch_process_image")
    public void preview(@RequestParam("processInstanceId") String processInstanceId) {
        try {
            InputStream is = getDiagram(processInstanceId);
            if (is == null)
                return;

            response.setContentType("image/png");

            BufferedImage image = ImageIO.read(is);
            OutputStream out = response.getOutputStream();
            ImageIO.write(image, "png", out);
            is.close();
            out.close();
        } catch (Exception ex) {
            log.error("查看流程图失败", ex);
        }
    }


    public InputStream getDiagram(String processInstanceId) {
        RuntimeService runtimeService = processEngine.getRuntimeService();
        HistoryService historyService = processEngine.getHistoryService();
        //获得流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        String processDefinitionId = StringUtils.EMPTY;
        if (processInstance == null) {
            //查询已经结束的流程实例
            HistoricProcessInstance processInstanceHistory =
                    historyService.createHistoricProcessInstanceQuery()
                            .processInstanceId(processInstanceId).singleResult();
            if (processInstanceHistory == null)
                return null;
            else
                processDefinitionId = processInstanceHistory.getProcessDefinitionId();
        } else {
            processDefinitionId = processInstance.getProcessDefinitionId();
        }

        //使用宋体
        String fontName = "宋体";
        //获取BPMN模型对象
        BpmnModel model = repositoryService.getBpmnModel(processDefinitionId);
        //获取流程实例当前的节点，需要高亮显示
        List<String> currentActs = Collections.EMPTY_LIST;
        if (processInstance != null)
            currentActs = runtimeService.getActiveActivityIds(processInstance.getId());

        return processEngine.getProcessEngineConfiguration()
                .getProcessDiagramGenerator()
                .generateDiagram(model, "png", currentActs, new ArrayList<String>(),
                        fontName, fontName, fontName, null, 1.0);
    }


}
